#include					"Arbitre.hpp"
#include					<iostream>

Arbitre::Arbitre(std::map<int, Square*> &map, bool doubleThreeRule, bool breakableFiveRule)
	: _map(map), _win(0), _doubleThreeRule(doubleThreeRule), _breakableFiveRule(breakableFiveRule)
{
	init(0, 1, 2);
	init(1, -1, -2);
	init(2, -19, -38);
	init(3, 19, 38);
	init(4, -20, -40);
	init(5, 20, 40);
	init(6, 18, 36);
	init(7, -18, -36);
}

Arbitre::~Arbitre()
{
}

void						Arbitre::init(int direction, int first, int second)
{
	int						*coords = new int[2];

	coords[0] = first;
	coords[1] = second;
	_directionCoords.insert(std::pair<int, int*>(direction, coords));
}

void						Arbitre::removeStone(int key, int direction)
{
	std::cout << "Taken Braah => " << direction << std::endl;
	_map[key + _directionCoords[direction][0]]->removeStone();
	_map[key + _directionCoords[direction][1]]->removeStone();
}

void						display(long long int var)
{
	unsigned int bit = 0;
	for (int i = 7 ; i >= 0 ; --i)
	{
		bit = (var >> i) & 1;
		std::cout << bit;
		if (i % 4 == 0 && i < 7)
			std::cout << " ";
	}
	std::cout << std::endl;
}

void						display64(long long int var)
{
	unsigned int bit = 0;
	for (int i = 63 ; i >= 0 ; --i)
	{
		bit = (var >> i) & 1;
		std::cout << bit;
		if (i % 4 == 0 && i < 63)
			std::cout << " ";
	}
	std::cout << std::endl;
}

char						Arbitre::purifyByte(char byte, int limit)
{
	for (int i = 7; i >= limit; --i)
		byte &= ~(1 << i);
	return (byte);
}

void						Arbitre::takeState(int key, char stonePattern, char colorPattern, int &deadStone, int direction, char colorMask)
{
/*	std::cout << "Info => ";
	display(stonePattern);
	std::cout << "Info color => ";
	display(colorPattern);
	std::cout << "Mask => ";
	display(TAKE_PATTERN);
	std::cout << "ColorMask => ";
	display(colorMask);*/
	
//		exit(1);*/
	//display(res);
	if (((stonePattern & TAKE_PATTERN) == TAKE_PATTERN) && ((stonePattern | TAKE_PATTERN) == TAKE_PATTERN) &&
		((colorPattern & colorMask) == colorMask) && ((colorPattern | colorMask) == colorMask))
	{
		removeStone(key, direction);	
		//deadStone += 2;
	}
//	std::cout << " Resultat => ";
//	display(res);
}

bool						Arbitre::winState(char stonePattern, char colorPattern, char colorMask)
{
	//std::cout << "Info => ";
	//display(byte);
		//std::cout << "Mask => ";
		//display(_winMasks[i]);
	
	if (((stonePattern & WIN_PATTERN) == WIN_PATTERN) && ((stonePattern | WIN_PATTERN) == WIN_PATTERN) &&
		((colorPattern & colorMask) == colorMask) && ((colorPattern | colorMask) == colorMask))
		{
		/*	std::cout << "Info => ";
			display(stonePattern);
			std::cout << "Info color => ";
			display(colorPattern);
			std::cout << "Mask => ";
			display(WIN_PATTERN);
			std::cout << "ColorMask => ";
			display(colorMask);*/
			_win = 1;
			std::cout << "Win" << std::endl;
			return (true);
		}
	return (false);
}

void						Arbitre::checkForWinner(int &deadStone, bool color)
{
	if (_win == 1)
		_win |= (color << 1);
	else if (deadStone >= 10)
	{
		_win |= (1 << 0);
		_win |= (color << 1);
	}
}

bool						Arbitre::ruleOfThree(char stonePattern, char colorPattern, char colorMask, char colorMask2, int i)
{
	std::cout << "Info => ";
	display(stonePattern);
	/*std::cout << "Info color => ";
	display(colorPattern);
	std::cout << "Mask1 => ";
	display(DOUBLE_THREE_PATTERN_1);
	std::cout << "Mask2 => ";
	display(DOUBLE_THREE_PATTERN_2);*/
	if (((stonePattern & DOUBLE_THREE_PATTERN_1) == DOUBLE_THREE_PATTERN_1) && ((stonePattern | DOUBLE_THREE_PATTERN_1) == DOUBLE_THREE_PATTERN_1) &&
		((colorPattern & colorMask) == colorMask) && ((colorPattern | colorMask) == colorMask))
		{
			std::cout << "-------------------------------Trois simple type 1-------------------------------" << std::endl;
			return (false);
		}
	if (((stonePattern & DOUBLE_THREE_PATTERN_2) == DOUBLE_THREE_PATTERN_2) && ((stonePattern | DOUBLE_THREE_PATTERN_2) == DOUBLE_THREE_PATTERN_2) &&
		((colorPattern & colorMask2) == colorMask2) && ((colorPattern | colorMask2) == colorMask2))
		{
			std::cout << "Info IN MON GARS => ";
			display(stonePattern);
			if ((i % 8) != 0 && (i / 8) != 2 && (i / 8) != 4 && (i / 8) != 6)
				std::cout << "-------------------------------Trois simple type 2-------------------------------" << std::endl;
			return (false);
		}
	return (true);
}

bool						Arbitre::breakableFive(int key)
{
	return (false);
}

char						Arbitre::swapBit(char bit)
{
	char					res = 0;

	for (int i = 3; i >= 0; --i)
		res |= (((bit >> (3 - i)) & 1) << i);
	return (res);
}

void						Arbitre::takeStateManager(int key, char stonePattern, char colorPattern, int &deadStone, int direction, char colorMask)
{
	if (!(direction % 8))
		takeState(key, purifyByte(swapBit(stonePattern), 3), purifyByte(swapBit(colorPattern), 3), deadStone, (direction / 4), colorMask);
	else
		takeState(key, purifyByte(stonePattern, 3), purifyByte(colorPattern, 3), deadStone, (direction / 4), colorMask);
}

void						Arbitre::ruleManager(char stonePattern, char colorPattern, char colorMask1, char colorMask2, int i)
{
	ruleOfThree(purifyByte(stonePattern, 4), purifyByte(colorPattern, 4), colorMask1, colorMask2, i);
}

int							Arbitre::check(int key, Box infoSquare, int &deadStone, bool color)
{
	infoSquare.states |= (1 << 4);
/*	if (color)
		infoSquare.states |= (1 << 1);*/
	display64(infoSquare.directions);

	for (int i = 0; i <= 28; ++i)
	{
		char				stonePattern = (char)infoSquare.directions;
		char				colorPattern = (char)(infoSquare.directions >> 32);

		if (!(i % 4))
			takeStateManager(key, stonePattern, colorPattern, deadStone, i, ((color) ? WHITE_PATTERN : BLACK_PATTERN));
		if ((i % 8) < 5)
		{
			if (_doubleThreeRule || _breakableFiveRule)
				ruleManager(stonePattern, colorPattern, ((color) ? DOUBLE_THREE_PATTERN_1 : DOUBLE_THREE_BLACK), ((color) ? DOUBLE_THREE_PATTERN_2 : DOUBLE_THREE_BLACK), i);
			winState(purifyByte(stonePattern, 4), purifyByte(colorPattern, 4), ((color) ? WIN_PATTERN : BLACK_WIN_PATTERN));
		}
		infoSquare.directions >>= 1;
	}
	std::cout << "------------------------------------------" << std::endl;
	checkForWinner(deadStone, color);
	return (0);
}

char					Arbitre::getWin()
{
	return (_win);
}